package com.zyl.unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author zhaoyl
 * @date 2024/5/15 21:26
 * @description 说明
 * list 多线程安全问题
 */
//java.util.ConcurrentModificationException 并发修改异常
public class ListTest {
    public static void main(String[] args) {
        //并发下ArrayList 多线程不安全
      //  List<String> list = new ArrayList<>();

       /* 解决方案1
         Vector:Vector是实现了List接口的子类，其底层是一个对象数组，
         维护了一个elementData数组，是线程安全的，Vector类的方法带有synchronized关键字，
         在开发中考虑线程安全中使用Vector。效率低*/
       // List<String>  list= new Vector<>();

        /* 解决方案2
        Collections.synchronizedList方法接受一个普通的List作为参数，并返回一个具有同步方法的List。
        可以使用这个同步的List在多线程环境中进行操作。尽管synchronizedList提供了一些基本的同步，
        但在复合操作（例如迭代和修改）时，仍然需要手动同步以确保线程安全。
        。*/
        //List<String> list = Collections.synchronizedList(new ArrayList<>());

        /*解决方案3 读写分离思想
        *1. CopyOnWriteArrayList（写数组的拷贝）是ArrayList的一个线程安全的变体，
        * CopyOnWriteArrayList和CopyOnWriteSet都是线程安全的集合，
        * 其中所有可变操作（add、set等等）都是通过对底层数组进行一次新的复制来实现的。
        2. 它绝对不会抛出ConcurrentModificationException的异常。
        * 因为该列表（CopyOnWriteArrayList）在遍历时将不会被做任何的修改。
        3.  CopyOnWriteArrayList适合用在“读多，写少”的“并发”应用中，
        * 换句话说，它适合使用在读操作远远大于写操作的场景里，比如缓存。
        * 它不存在“扩容”的概念，每次写操作（add or remove）都要copy一个副本，
        * 在副本的基础上修改后改变array引用，所以称为“CopyOnWrite”，因此在写操作是加锁，
        * 并且对整个list的copy操作时相当耗时的，过多的写操作不推荐使用该存储结构。
        * CopyOnWriteArrayList类的最大优点在于读取时无需加锁，非常适合读多写少的并发场景，
        * */
        List<String> list = new CopyOnWriteArrayList<>();

        //开10个线程添加
        for (int i=0;i<=10;i++){
         new Thread(()->{
             list.add(UUID.randomUUID().toString().substring(0,5));
             System.out.println(list);
         },String.valueOf(i)).start();
        }
    }
}
